package com.chezhujie.www.controller;

import com.alibaba.fastjson.JSONObject;
import com.chezhujie.www.core.StaticMap;
import com.chezhujie.www.domain.*;
import com.chezhujie.www.domain.vo.AccessToken;
import com.chezhujie.www.domain.vo.WeixinInfo;
import com.chezhujie.www.enums.OrderStatus;
import com.chezhujie.www.service.*;
import com.xy.user.base.controller.BaseController;
import com.xy.core.utils.*;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import weixin.popular.api.PayMchAPI;
import weixin.popular.api.TicketAPI;
import weixin.popular.api.TokenAPI;
import weixin.popular.bean.paymch.*;
import weixin.popular.bean.ticket.Ticket;
import weixin.popular.bean.token.Token;
import weixin.popular.support.ExpireKey;
import weixin.popular.support.expirekey.DefaultExpireKey;
import weixin.popular.util.PayUtil;
import weixin.popular.util.SignatureUtil;
import weixin.popular.util.StreamUtils;
import weixin.popular.util.XMLConverUtil;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.util.*;


/**
 * Created by 汤伟杰 on 2017/5/8.
 */
//@Controller
//@RequestMapping("/weixin")
public class WeixinController extends BaseController {
    private static final Logger log = LoggerFactory.getLogger(WeixinController.class);
    @Autowired
    private WeixininfoService weixininfoService;
    @Autowired
    private CzjorderService czjorderService;
    @Autowired
    private CzjactivityService czjactivityService;
    @Autowired
    private CzjtordermemberService czjtordermemberService;
    @Autowired
    private CzjuserinfoService czjuserinfoService;
    @Autowired
    private CzjusermessService czjusermessService;
    @Autowired
    private CzjweixinvoucherService czjweixinvoucherService;
    @Autowired
    private CzjpayorderService czjpayorderService;
    @Autowired
    private CzjawarduseService czjawarduseService;
    @Autowired
    private CzjorderdetailService czjorderdetailService;
    @Autowired
    private CzjcommodityService czjcommodityService;
    @Autowired
    private CzjweixininfoService czjweixininfoService;
    @Autowired
    private CzjawardstockService czjawardstockService;
    @Autowired
    private CzjusecouponService czjusecouponService;

    /**
     * 首页响应
     * @param request
     * @param resp
     * @param model
     * @return
     * @throws IOException
     */
    @RequestMapping("returnUrl.do")
    public String returnUrl(HttpServletRequest request, HttpServletResponse resp,
                        ModelMap model) throws IOException {
        String basePath = request.getRequestURL().substring(0,request.getRequestURL().lastIndexOf(request.getRequestURI()));
        basePath+=request.getContextPath()+"/index.html?access_type=1";
        String encode = getURLEncoderString(basePath);
        encode = encode.toLowerCase();
//        String url =  "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+StaticMap.appid+"&redirect_uri="+encode+"%3facc=1&response_type=code&scope=snsapi_userinfo#wechat_redirect";
//        resp.sendRedirect(url);
        model.addAttribute("url",encode);
        model.addAttribute("appid",StaticMap.appid);
        return "weixinLogin";

    }

    /**
     * 获取微信配置信息
     * @param url
     * @param req
     * @param resp
     * @param model
     * @throws IOException
     */
    @RequestMapping("getInfo.do")
    public void getInfo(@RequestParam(required = true) String url,
                        HttpServletRequest req, HttpServletResponse resp,
                        ModelMap model) throws IOException {
        try {
//            url = "http://www.51d1d.com/chezhujie/html/jssdk/index.html";
            if(StaticMap.getAccessToken()==null){
                StaticMap.setAccessToken(new AccessToken());
            }
            AccessToken accessToken = StaticMap.getAccessToken();
            if(accessToken.getEndtime()==null||accessToken.getEndtime()<=System.currentTimeMillis()){
                String token = weixininfoService.getAccessToken();
                String ticket = weixininfoService.getTicket(token);
                accessToken.setAccess_token(token);
                accessToken.setTicket(ticket);
                accessToken.setCreatetime(new Date());
                accessToken.setEndtime(System.currentTimeMillis()+60*1000);
                accessToken.setExpires_in(0);
            }
            Map map = WeixininfoService.sign(accessToken.getTicket(), url,StaticMap.appid);

            jsonResult(1,"","",map,resp);
        } catch (Exception e) {
            e.printStackTrace();
            jsonResult(0,"00","出错："+e.getMessage(),"",resp);
        }
    }

    /**
     * 微信测试
     * @param url
     * @param req
     * @param resp
     * @param model
     * @throws IOException
     */
    @RequestMapping("getInfoDemo.do")
    public void getInfoDemo(String url,

                        HttpServletRequest req, HttpServletResponse resp,
                        ModelMap model) throws IOException {
        try {
            Token token = TokenAPI.token(StaticMap.appid,StaticMap.secret);
            Ticket ticket = TicketAPI.ticketGetticket(token.getAccess_token());
            String us = req.getRequestURI();
            Map map = WeixininfoService.sign(ticket.getTicket(), url,StaticMap.appid);
            jsonResult(1,"","",map,resp);
        } catch (Exception e) {
            e.printStackTrace();
            jsonResult(0,"00","出错："+e.getMessage(),"",resp);
        }
    }


    /**
     * URL 转码
     *
     * @return String
     * @author lifq
     * @date 2015-3-17 下午04:10:28
     */
    public static String getURLEncoderString(String str) {
        String result = "";
        if (null == str) {
            return "";
        }
        try {
            result = java.net.URLEncoder.encode(str, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 获取微信用户信息
     * @param code
     * @param req
     * @param resp
     * @param model
     * @throws Exception
     */
    @RequestMapping("getWeixinInfo.do")
    public void getOpenId(@RequestParam(required = true) String code,
                         String appid,String secret,
                         Integer userinfoId,
                        HttpServletRequest req, HttpServletResponse resp,
                        ModelMap model) throws Exception {

        try {

            if(StringUtils.isBlank(appid)){
                appid = StaticMap.appid;
            }
            if(StringUtils.isBlank(secret)){
                secret = StaticMap.secret;
            }
            WeixinInfo weixin = weixininfoService.getWeixinInfo(code, appid, secret);


            if(userinfoId!=null){
                Czjuserinfo userinfo = czjuserinfoService.queryByUserinfoId(userinfoId);
                if(userinfo==null){
                    jsonResult(0,"035","用户不存在！","",resp);
                    return ;
                }
                Czjusermess usermess = czjusermessService.queryByUserinfoId(userinfoId);
                if(usermess==null){
                    usermess =new Czjusermess();
                    usermess.setUsermessId(UUIDUtils.getUUID());
                    usermess.setUserinfoId(userinfoId);
                    czjusermessService.insertUsermess(usermess);
                    usermess = czjusermessService.queryByUserinfoId(userinfoId);
                }
                //用户头像、性别、昵称、地区
//                weixin.getHeadimgurl()
                userinfo.setNickname(weixin.getNickname());
                usermess.setReginon(weixin.getCity());
                //1男2女
                //微信0女1男
                 if(weixin.getSex()==0){
                     usermess.setSex(2);
                 }else if(weixin.getSex()==1){
                     usermess.setSex(1);
                 }
                String basePath = req.getSession().getServletContext().getRealPath("/");
                String path = basePath+"upload/usermess/";
                Fileupload.createDir(basePath+"upload/usermess/");
                String type = ".jpg";
                String filename = usermess.getUsermessId() + "-" + System.currentTimeMillis() + type;
                FileuploadHttp.download(weixin.getHeadimgurl(),filename,path);
                usermess.setPicPath("/upload/usermess/"+filename);
                czjusermessService.updateUsermess(usermess);
                czjuserinfoService.updateCzjuserinfo(userinfo);


            }

            jsonResult(1,"","",weixininfoService.getWeixinInfo(code,appid,secret),resp);
        } catch (Exception e) {
            e.printStackTrace();
            jsonResult(0,"","获取微信信息出错！"+e.getMessage(),"",resp);
        }


    }

    /**
     * 通过微信openid获取微信信息
     * @param openId
     * @param appid
     * @param secret
     * @param userinfoId
     * @param req
     * @param resp
     * @param model
     * @throws Exception
     */
    @RequestMapping("getWeixinInfoByOpenId.jn")
    public void getWxOpenId(@RequestParam(required = true) String openId,
                          String appid,String secret,
                          Integer userinfoId,
                          HttpServletRequest req, HttpServletResponse resp,
                          ModelMap model) throws Exception {
        Czjweixininfo czjweixininfo = czjweixininfoService.queryById(openId);
        jsonResult(1,"","",czjweixininfo,resp);
        return ;

    }


    /**
     * 得到用户基本信息(包括是否关注公众号)
     * @param code
     * @param req
     * @param resp
     * @param model
     */
    @RequestMapping("getWeixinInfoGzh.do")
    public void getUserInfo(@RequestParam(required = true) String code,
                            HttpServletRequest req, HttpServletResponse resp,
                            ModelMap model){
        try {
//            WeixinInfo weixininfo = recommendpicService.getWeixinUserinfo(code);//得到微信用户信息
//            AccessOpenId openIdEntity = StaticMap.getAccessOpenIdMap(code);
            Map<String,Object> map = weixininfoService.getWeixinGongzhonghao(code,StaticMap.appid,StaticMap.secret);
            jsonResult(1,"","",map,resp);
        } catch (Exception e) {
            e.printStackTrace();
            jsonResult(0,"99",e.getMessage(),"",resp);
        }
    }

    /**
     * 支付 配置验证信息
     * @param request
     * @param response
     * @param model
     * @throws ServletException
     * @throws IOException
     */
    @RequestMapping("payMchjs.jn")
    public void payMchJs(@RequestParam(required = true)String openId,
                         @RequestParam(required = true)String orderNo,//支付订单号
            String appid2,
                         HttpServletRequest request, HttpServletResponse response,
                          ModelMap model) throws Exception {

        try {

            String path = request.getRequestURL().substring(0, request.getRequestURL().lastIndexOf("/"))+"/payMchNotify.jn";
            String notifyUrl = path;//支付回调链接
//        openId = "oRYMns_SBJTs5-FQREG3aACMSE-Q";

            String appid=StaticMap.appid;
            String mch_id=StaticMap.mch_id;
            String wx_openid = openId;//"oRYMns_SBJTs5-FQREG3aACMSE-Q"
            String key = StaticMap.payKey;

            if(org.apache.commons.lang.StringUtils.isNotBlank(appid2)){
                appid=appid2;
            }



            String title = "商品信息";
            String money = "";//单位分 0.01元
            Map<String, Object> order = new HashMap<String, Object>();
            String type = orderNo.substring(8,9);
            if("1".equals(type)){//活动
                order = czjactivityService.getOrderedByNo(orderNo);
            }else if("2".equals(type)){//商品
                order = czjorderService.getOrderedByNo(orderNo);

                Czjorderdetail czjorderdetail = czjorderdetailService.queryByCode(orderNo);
                if(order==null){
                    jsonResult(0,"73","订单不存在","",response);
                    return;
                }

                Czjcommodity commodity = czjcommodityService.queryById(czjorderdetail.getCommodityId());
                if(commodity.getDelFlag()==1||commodity.getSoldOut()==1){
                    System.out.println(LocalDateTime.getDateStr(new Date())+"    "+"商品已下架，请手动取消订单！");
                    jsonResult(0,"71","商品已下架，请手动取消订单！","",response);
                    return;
                }
            }else if("3".equals(type)){//会员
                order = czjtordermemberService.getOrderedByNo(orderNo);
            }else{
                jsonResult(0,"72","支付类型不正确，只能是1（活动）或者2（商品）","",response);
                return;
            }
            if(order==null||org.apache.commons.lang.StringUtils.isBlank(String.valueOf(order.get("money")))){
                jsonResult(0,"73","订单不存在或者订单金额信息为空","",response);
                return;
            }
            //payPackage 的商品信息,openid 可以通过sns,或事件获取。
           if(null==order.get("title")){
                title="车主节-订单支付";
            }else{
                title = String.valueOf(order.get("title"));
                if(title.length()>=50){
                    title = title.substring(0,50);
                }
            }

            money = String.valueOf(order.get("money"));

            Unifiedorder unifiedorder = new Unifiedorder();
            unifiedorder.setAppid(appid);
            unifiedorder.setMch_id(mch_id);
            unifiedorder.setNonce_str(UUID.randomUUID().toString().toString().replace("-", ""));

            unifiedorder.setOpenid(wx_openid);
            unifiedorder.setBody(title);
            unifiedorder.setOut_trade_no(orderNo);
            unifiedorder.setTotal_fee(new BigDecimal(money).multiply(new BigDecimal(100)).intValue()+"");//单位分 0.01元
            unifiedorder.setSpbill_create_ip(request.getRemoteAddr());//IP
            unifiedorder.setNotify_url(notifyUrl);
            unifiedorder.setTrade_type("JSAPI");//JSAPI，NATIVE，APP，WAP
            //统一下单，生成预支付订单
            UnifiedorderResult unifiedorderResult = PayMchAPI.payUnifiedorder(unifiedorder,key);

            if(!"SUCCESS".equals(unifiedorderResult.getReturn_code())){
                jsonResult(0,"89",unifiedorderResult.getReturn_msg(),"",response);
                return;
            }
            if(!"SUCCESS".equals(unifiedorderResult.getResult_code())){
                jsonResult(0,"89",unifiedorderResult.getErr_code()+"-"+unifiedorderResult.getErr_code_des(),"",response);
                return;
            }

            //@since 2.8.5  API返回数据签名验证
            if(unifiedorderResult.getSign_status() !=null && unifiedorderResult.getSign_status()){
                MchBase mb = unifiedorderResult;
                if("FAIL".equals(mb.getResult_code())){
                    jsonResult(0,mb.getErr_code_des().split(" ")[0],mb.getErr_code_des().split(" ")[1],"",response);
                    return;
                }
                String json = PayUtil.generateMchPayJsRequestJson(unifiedorderResult.getPrepay_id(), appid, key);

                Map map = JSONObject.parseObject(json, Map.class);
                jsonResult(1,"",JSONObject.toJSONString(unifiedorder),map,response);
                return;
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("",e);
        }
        jsonResult(0,"89","请求支付失败！","",response);
    }

    /**
     * 微信支付完成回调函数
     */
    //重复通知过滤
    private static ExpireKey expireKey = new DefaultExpireKey();
    @RequestMapping("payMchNotify.jn")
    public void payMchNotify(HttpServletRequest request, HttpServletResponse response,
                             ModelMap model) throws IOException {
        try {
            String key = StaticMap.payKey;
            //获取请求数据
            String xmlData = StreamUtils.copyToString(request.getInputStream(), Charset.forName("utf-8"));
            //将XML转为MAP,确保所有字段都参与签名验证
            Map<String,String> mapData = XMLConverUtil.convertToMap(xmlData);
            //转换数据对象
            MchPayNotify payNotify = XMLConverUtil.convertToObject(MchPayNotify.class,xmlData);

            //已处理 去重
            if(expireKey.exists(payNotify.getTransaction_id())){
                MchBaseResult baseResult = new MchBaseResult();
                baseResult.setReturn_code("SUCCESS");
                baseResult.setReturn_msg("OK");
                response.getOutputStream().write(XMLConverUtil.convertToXML(baseResult).getBytes());
                return;
            }
            //签名验证
            if(SignatureUtil.validateSign(mapData,key)){
                //@since 2.8.5
                payNotify.buildDynamicField(mapData);

                expireKey.add(payNotify.getTransaction_id());
                MchBaseResult baseResult = new MchBaseResult();
                baseResult.setReturn_code("SUCCESS");
                baseResult.setReturn_msg("OK");
                try {
                    weixininfoService.insertWeixinVoucher(payNotify);//插入微信支付凭证到数据库
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("生成微信凭证失败！",e);
                }

                response.getOutputStream().write(XMLConverUtil.convertToXML(baseResult).getBytes());
            }else{
                MchBaseResult baseResult = new MchBaseResult();
                baseResult.setReturn_code("FAIL");
                baseResult.setReturn_msg("ERROR");
                response.getOutputStream().write(XMLConverUtil.convertToXML(baseResult).getBytes());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("生成微信凭证失败！2",e);
        }
    }
    @RequestMapping("refund.jn")
    public void refund(String orderno,HttpServletRequest request, HttpServletResponse response,
                             ModelMap model) throws IOException {
       try{
           SecapiPayRefundResult obj = weixininfoService.payRefund(orderno);
           jsonResult(1,"","",obj,response);
       }catch (Exception e){
           log.error("#error:",e);
           e.printStackTrace();
           jsonResult(0,"","#error"+e,"",response);
       }

    }
    /** 发红包 */
    @RequestMapping("sendredpack.jn")
    public void sendredpack(String orderCode,String openId,String userinfoId,Integer amount,HttpServletRequest request, HttpServletResponse response,
                             ModelMap model) throws IOException {
        String xml = "";
       try{
           String datestr = LocalDateTime.getDate(new Date(),"yyyy-MM-dd HH");
           if (!StringUtils.isBlank(request.getParameter("ck"))) {
               if (MD5Util.md5(datestr+" tangwj").equals(request.getParameter("ck"))) {
                   xml = weixininfoService.sendredpack(orderCode,openId,userinfoId,amount, request);
               }
           }
           System.out.println(LocalDateTime.getDateStr(new Date())+"    "+xml);

           Document document = DocumentHelper.parseText(xml);
           Map<String, String> map = Dom4jUtils.Dom2Map(document);
           if("SUCCESS".equals(map.get("return_code"))){
               if("FAIL".equals(map.get("result_code"))){
                   jsonResult(0,map.get("err_code"),map.get("err_code_des"),"失败",response);
                   return;
               }
           }else{
               jsonResult(0,map.get("err_code"),map.get("err_code_des"),"失败2",response);
               return;
           }
           jsonResult(1,"","",xml,response);
       }catch (Exception e){
           log.error("#error:",e);
           e.printStackTrace();
           jsonResult(0,"",xml+"\n#error"+e,"",response);
       }

    }



    /**
     * 更新红包领取状态
     * @param redpackId
     * @param request
     * @param response
     * @param model
     * @throws IOException
     */
    @RequestMapping("updateRedpack.jn")
    public synchronized void updateRedpack(String redpackId,String openId,String code,HttpServletRequest request, HttpServletResponse response,
                             ModelMap model) throws IOException {
       try{
               Czjawarduse czjawarduse = czjawarduseService.queryById(redpackId);
               Czjawardstock awardstock = czjawardstockService.queryById(czjawarduse.getAwardId());
               Map<String, Object> map = new HashMap<String, Object>();
               map.put("alreadyReceived", 0);
               if (czjawarduse == null || awardstock == null) {
                   jsonResult(0, "68", "该红包不存在！", "", response);
                   return;
               }
               if (czjawarduse.getStatus() == OrderStatus.RECEIVED.getIndex()) {//已领取，则返回一个标识为已领取
                   map.put("alreadyReceived", 1);

                   jsonResult(1, "", "红包领取成功", map, response);
                   return;
               }

               if (czjawarduse.getStatus() == OrderStatus.UNRECEIVED.getIndex()) {//发送红包开始

                   //发送微信红包 开始


                   if (StringUtils.isNotBlank(code)) {
                       WeixinInfo weixin = weixininfoService.getWeixinInfo(code, StaticMap.appid, StaticMap.secret);
                       openId = weixin.getOpenid();
                   }
                   if (StringUtils.isBlank(openId)) {
                       jsonResult(0, "79", "openId不能为空", map, response);
                       return;
                   }
                   if (System.currentTimeMillis() > awardstock.getValidDate().getTime()) {
                       jsonResult(0, "87", "该红包已过期", map, response);
                       return;
                   }

                   Integer price = awardstock.getPrice().multiply(new BigDecimal(100)).intValue();
                   Integer smallprice = awardstock.getSmallprice().multiply(new BigDecimal(100)).intValue();
                   int random = random(smallprice, price);
                   String xml = weixininfoService.sendredpack(czjawarduse.getOrderNo(), openId, czjawarduse.getUserInfoId(), random,request);
                   Document document = DocumentHelper.parseText(xml);
                   Map<String, String> result = Dom4jUtils.Dom2Map(document);
                   if ("SUCCESS".equals(result.get("return_code"))) {
                       if ("FAIL".equals(result.get("result_code"))) {
                           jsonResult(0, result.get("err_code"), result.get("err_code_des"), "失败", response);
                           return;
                       }
                   } else {
                       jsonResult(0, result.get("err_code"), result.get("err_code_des"), "失败2", response);
                       return;
                   }
                   czjawarduse.setStatus(OrderStatus.RECEIVED.getIndex());
                   BigDecimal dm = new BigDecimal(random).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
                   czjawarduse.setPrice(dm);
                   czjawarduseService.updateCzjawarduse(czjawarduse);
                   czjusecouponService.businessSave(redpackId,czjawarduse.getOrderNo());//保存使用过的红包
                   //发送微信红包 结束
                   jsonResult(1, "", "红包领取成功", map, response);
                   return;


               } else {
                   jsonResult(0, "69", "红包领取状态不对！", "", response);
                   return;
               }




       }catch (Exception e){
           log.error("#error:",e);
           e.printStackTrace();
           jsonResult(0,"","#error:"+e,"",response);
       }

    }

    /**
     * 随机获取区间里的数
     * @param smallprice
     * @param price
     * @return
     */
    private int random(Integer smallprice, Integer price) throws Exception {
        if(smallprice==null&&price!=null){
            return price;
        }
        if(smallprice!=null&&price==null){
            return smallprice;
        }
        if(smallprice==null&&price==null){
            throw new Exception("该红包没有填写价格！");
        }
        if(smallprice>price){
            throw new Exception("该红包最小金额大于红包最大金额");
        }
        if(smallprice!=null&&price!=null){
            if(smallprice.equals(price)){
                return smallprice;
            }
            Random rand = new Random();
            return rand.nextInt(price-smallprice+1) + smallprice;
        }
        throw new Exception("该红包没有填写价格！");
    }


}
